/**
 * Created by jianglinjie on Mon Oct 09 2017
 * @flow
 */
'use strict';
import * as LoginType from '../../constants/LoginType';
import { FetchClient, JSONRequest } from '../../network';
import ConfigService from '../config';
import type { UserInfo, LoginParam, LoginResult, LogoutResult } from '../../serviceTypes';
import { md5 } from '../../utils/StringUtils';
import AuthStore from './AuthStore';
import ClientLog from '../log';
import Emitter from '../emitter';
import ServiceError, { isServiceError } from '../error';
import { ErrorCode } from '../../constants';
import * as ServiceEventNames from '../constants/ServiceEventNames';
const LOGIN_PATH = '/users/actions/login';
const LOGOUT_PATH = '/users/actions/logout';

class AuthService {
  store: AuthStore = new AuthStore();

  async getToken(): Promise<string> {
    let result = await this.store.loadLoginResult();
    if (!result) {
      return '';
    }

    if (result.expireAt < Date.now()) {
      ClientLog.log('getToken token expire');
      //过期自动登录
      let newResult = await this.autoLogin();
      if (newResult) {
        //自动登录成功 返回新的token
        return newResult.token;
      } 
    } 

    return result.token;    
  }

  async getCurrentUserInfo(): Promise<?UserInfo> {
    let result = await this.store.loadLoginResult();
    if (!result) {
      return null;
    }    

    return result.userInfo;
  }

  async isLogined(): Promise<boolean> {
    let userInfo = await this.getCurrentUserInfo();
    if (!userInfo) {
      return false;
    }  

    return true;
  }

  async getRecentLoginedUserInfos(): Promise<Array<UserInfo>> {
    let userInfos = await this.store.getRecentLoginedUserInfos();
    return userInfos;
  }

  async loginWithAccount(
    account: string, 
    pwd: string, 
    encrypted: boolean = false
  ): Promise<LoginResult> {
    let param = {
      account: account,
      encryptPwd: encrypted ? pwd : md5(pwd)
    };

    let result = await this.login(LoginType.ACCOUNT_ENCRYPTPWD, param);

    return result;
  }

  async loginWithPhoneCaptcha(phone: string, captcha: string): Promise<LoginResult> {
    let param = {
      phone: phone,
      captcha: captcha
    };

    let result = await this.login(LoginType.PHONE_CAPTCHA, param);

    return result;
  }

  async autoLogin(): Promise<?LoginResult> {
    let result = await this.store.loadLoginResult();
    if (!result) {
      Emitter.emit(
        ServiceEventNames.AUTH_SERVICE_ON_AUTOLOGIN_FAILED, 
        new ServiceError(ErrorCode.CLIENT_NOT_LOGIN_IN, '客户端的未登录'));      
      return null;
    }

    let account = result.userInfo.userName || result.userInfo.phone;
    let encryptPwd = result.userInfo.encryptPwd;
    if (account && encryptPwd) {
      try {
        ClientLog.info('begin autoLogin for %o', account);                
        let result = await this.loginWithAccount(account, encryptPwd, true);
        return result;     
      } catch (error) {
        ClientLog.error('autoLogin error %o', error);
        Emitter.emit(ServiceEventNames.AUTH_SERVICE_ON_AUTOLOGIN_FAILED, error);
        
        //todo 需要判断错误类型 移除之前的登录态
        await this.store.removeLoginResult();
        Emitter.emit(ServiceEventNames.AUTH_SERVICE_ON_LOGIN_STATE_CHANGE, false);
        return null;
      }
    } else {
      Emitter.emit(
        ServiceEventNames.AUTH_SERVICE_ON_AUTOLOGIN_FAILED, 
        new ServiceError(ErrorCode.REQUIRE_ACCOUNT_OR_PWD, '缺少账户或密码'));      
      return null;
    }
  }

  async logout(): Promise<LogoutResult> {
    let token = await this.getToken();
    if (!token) {
      return {
        result: false
      };
    }

    await this.store.removeLoginResult();
    Emitter.emit(ServiceEventNames.AUTH_SERVICE_ON_LOGIN_STATE_CHANGE, false);
    
    let param = {
      token: token
    };

    let request = new JSONRequest(
      ConfigService.apiBaseHost + LOGOUT_PATH, 
      null, 
      param
    );

    try {
      let body = await FetchClient.start(request);
      return body.data;
    } catch (error) {
      ClientLog.error('logout error %o', error);
      return {
        result: false
      };  
    }
  }

  async login(type: string, param: LoginParam): Promise<LoginResult> {
    let request = new JSONRequest(
      ConfigService.apiBaseHost + LOGIN_PATH, 
      { type: type }, 
      param
    );

    let body = await FetchClient.start(request);
    let loginResult = body.data;
    
    await this.store.saveLoginResult(loginResult);
    await this.store.addRecentLoginedUserInfo(loginResult.userInfo);

    Emitter.emit(ServiceEventNames.AUTH_SERVICE_ON_LOGIN_STATE_CHANGE, true);
    
    return loginResult;
  }

  isAuthError(error): boolean {
    if (isServiceError(error)) {
      if (error.errorCode === '') {
        return true;
      }
    }

    return false;
  }
}

export default new AuthService();
